package com.snow.common.config;

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.TrustStrategy;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

/**
 * All rights Reserved, Designed By www.cusc.com
 *
 * @author yanke
 * @Title: ResttemplateConfig
 * @Package com.snow.common.config
 * @Description:类描述
 * @Email yanke@cu-sc.com
 * @version: v1.0.0
 * @date: 2021/4/23/0023 15:54
 * @Copyright: 2021  www.faw.com.cn Inc. All rights reserved. <br/>
 * Modification History:<br/>
 * Date         Author          Version            Description<br/>
 * *---------------------------------------------------------*<br/>
 * 2021/4/23/0023     Administrator           v1.0.0               修改原因<br/>
 * @since JDK 1.8
 */
@Configuration
public class RestTemplateConfig {

    private final static Integer MAX_TOTAL = 10;

    private final static Integer DEFAULT_MAX_PERROUTE = 5;

    private final static Integer CONNECT_TIMEOUT = 5000;

    private final static Integer CONNECTION_REQUEST_TIMEOUT = 3000;

    private final static Integer SOCKET_TIMEOUT = 5000;

    private final static boolean STALE_CONNECTION_CHECK_ENABLED = false;

    private final static Integer VALIDATE_AFTER_INACTIVITY = 600;

    @Bean
    public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient());
        return new RestTemplate(requestFactory);
    }

    private HttpClient httpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", csf())
                .build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        connectionManager.setMaxTotal(MAX_TOTAL); // 最大连接数
        connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PERROUTE);    //单个路由最大连接数
        connectionManager.setValidateAfterInactivity(VALIDATE_AFTER_INACTIVITY); // 最大空间时间

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT)        //服务器返回数据(response)的时间，超过抛出read timeout
                .setConnectTimeout(CONNECT_TIMEOUT)      //连接上服务器(握手成功)的时间，超出抛出connect timeout
//                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK_ENABLED) // 提交前检测是否可用
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)//从连接池中获取连接的超时时间，超时间未拿到可用连接，会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .build();

        return HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    private ConnectionSocketFactory csf() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        return new SSLConnectionSocketFactory(sslContext);
    }
}
